package com.yic.module.device.service.refund;

import cn.hutool.core.util.ObjectUtil;
import com.yic.framework.security.core.util.SecurityFrameworkUtils;
import com.yic.module.device.dal.dataobject.device.DeviceDO;
import com.yic.module.device.dal.dataobject.receive.ReceiveDO;
import com.yic.module.device.service.device.DeviceService;
import com.yic.module.device.service.resume.ResumeService;
import com.yic.module.system.api.user.AdminUserApi;
import com.yic.module.system.api.user.dto.AdminUserRespDTO;
import com.yic.module.system.enums.common.ApproveEnum;
import com.yic.module.system.enums.dict.DeviceResumeTypeEnum;
import com.yic.module.system.enums.dict.DeviceUseStatusEnum;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.util.*;
import com.yic.module.device.controller.admin.refund.vo.*;
import com.yic.module.device.dal.dataobject.refund.RefundDO;
import com.yic.framework.common.pojo.PageResult;

import com.yic.module.device.convert.refund.RefundConvert;
import com.yic.module.device.dal.mysql.refund.RefundMapper;

import static com.yic.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yic.module.device.enums.ErrorCodeConstants.*;

/**
 * 退还申请 Service 实现类
 *
 * @author 系统管理员
 */
@Service
@Validated
public class RefundServiceImpl implements RefundService {

    @Resource
    private RefundMapper refundMapper;
    @Resource
    private DeviceService deviceService;
    @Resource
    private ResumeService resumeService;
    @Resource
    private AdminUserApi adminUserApi;

    @Override
    public Long createRefund(RefundCreateReqVO createReqVO) {
        validateCreateOrUpdate(null, createReqVO.getCode());
        checkDevice(createReqVO.getDeviceId());
        // 插入
        RefundDO refund = RefundConvert.INSTANCE.convert(createReqVO);
        AdminUserRespDTO user = adminUserApi.getUser(SecurityFrameworkUtils.getLoginUserId());
        refund.setUserId(user.getId());
        refund.setDeptId(user.getDeptId());
        refundMapper.insert(refund);
        // 返回
        return refund.getId();
    }

    private void checkDevice(Long deviceId){
        DeviceDO device = deviceService.get(deviceId);
        // 校验当前设备是否被领用
        if (!DeviceUseStatusEnum.USEING.getDeviceUseStatus().equals(device.getUseStatus())) {
            throw exception(REFUND_NOT_ALLOW);
        }
    }

    @Override
    public void updateRefund(RefundUpdateReqVO updateReqVO) {
        /// 校验存在
        RefundDO refundDO = validateCreateOrUpdate(updateReqVO.getId(), updateReqVO.getCode());
        if (!ApproveEnum.WAIT.getApprove().equals(refundDO.getApprove())){
            throw exception(REFUND_NOT_CHANGE);
        }
        checkDevice(updateReqVO.getDeviceId());
        // 更新
        RefundDO updateObj = RefundConvert.INSTANCE.convert(updateReqVO);
        refundMapper.updateById(updateObj);
    }

    @Override
    public void deleteRefund(Long id) {
        // 校验存在
        RefundDO refundDO = validateRefundExists(id);
        if (!ApproveEnum.WAIT.getApprove().equals(refundDO.getApprove())){
            throw exception(REFUND_NOT_CHANGE);
        }
        // 删除
        refundMapper.deleteById(id);
    }

    private RefundDO validateCreateOrUpdate(Long id, String code){
        return validateCodeExist(id, code);
    }

    private RefundDO validateCodeExist(Long id, String code){
        RefundDO refundDO = refundMapper.selectByCode(code);
        if (ObjectUtil.isEmpty(refundDO)){
            return refundDO;
        }
        if (id == null){
            throw exception(REFUND_CODE_EXISTS);
        }
        if (!id.equals(refundDO.getId())){
            throw exception(REFUND_CODE_EXISTS);
        }
        return refundDO;
    }

    private RefundDO validateRefundExists(Long id) {
        RefundDO refundDO = refundMapper.selectById(id);
        if (refundDO == null) {
            throw exception(REFUND_NOT_EXISTS);
        }
        return refundDO;
    }

    @Override
    public RefundDO getRefund(Long id) {
        return refundMapper.selectById(id);
    }

    @Override
    public List<RefundDO> getRefundList(Collection<Long> ids) {
        return refundMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<RefundDO> getRefundPage(RefundPageReqVO pageReqVO) {
        return refundMapper.selectPage(pageReqVO);
    }

    @Override
    public List<RefundDO> getRefundList(RefundExportReqVO exportReqVO) {
        return refundMapper.selectList(exportReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void approveRefund(Long id) {
        RefundDO refundDO = validateRefundExists(id);
        if (!ApproveEnum.WAIT.getApprove().equals(refundDO.getApprove())) {
            throw exception(REFUND_NOT_CHANGE);
        }
        refundDO.setApprove(ApproveEnum.PASS.getApprove());
        refundDO.setApproveTime(LocalDateTime.now());
        refundMapper.updateById(refundDO);
        // 更新设备台账信息
        deviceService.updateReceiveInfo(refundDO.getDeviceId(), null, "", null, null, null, DeviceUseStatusEnum.STOP.getDeviceUseStatus());
        // 登记设备履历表
        resumeService.createResume(refundDO.getDeviceId(), DeviceResumeTypeEnum.REFUND.getDeviceResumeType(), "设备退还", refundDO.getId(), refundDO.getUserId(), refundDO.getCreateTime());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelRefund(Long id) {
        RefundDO refundDO = validateRefundExists(id);
        if (!ApproveEnum.PASS.getApprove().equals(refundDO.getApprove())) {
            throw exception(REFUND_NOT_CHANGE);
        }
        refundDO.setApprove(ApproveEnum.WAIT.getApprove());
        refundMapper.updateById(refundDO);
        // 更新设备台账
        deviceService.updateReceiveInfo(refundDO.getDeviceId(), null, "", null, null, null, DeviceUseStatusEnum.USEING.getDeviceUseStatus());
        // 删除设备履历表
        resumeService.deleteResumeBySourceId(id, DeviceResumeTypeEnum.REFUND.getDeviceResumeType());
    }

}
